home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1997 / HAM Radio 1997.iso / vcls / msggrab / sizer.pas < prev   
Pascal/Delphi Source File  |  1996-04-08  |  7KB  |  248 lines

  1. unit Sizer;
  2.  
  3. interface
  4.  
  5. uses
  6.     Messages, WinTypes, Classes, WinProcs, Controls, Forms, SysUtils;
  7.  
  8. type ENonWindowOwner=class(Exception);
  9.  
  10. {------------------------------------------------------------------}
  11. {--- Message Grabber ----------------------------------------------}
  12. {------------------------------------------------------------------}
  13. {Provides a component basis from which to trap messages sent to the form.
  14. To override specific messages, descend from TMessageGrabber and either
  15. add a message response method (such as WMGetMinMaxInfo), or override
  16. the virtual method WndProc}
  17.  
  18. type TMessageGrabber = class(TComponent)
  19.         private
  20.             OwnerWndProc:TFarProc;
  21.             MyWndProc:TFarProc;
  22.             OwnerProcGrabbedQ:Boolean;
  23.         protected
  24.             procedure WndProc(var Msg:TMessage); virtual;
  25.             procedure DefaultHandler(var Msg); override;
  26.             procedure WMDestroy(var Msg:TWMDestroy); message WM_Destroy;
  27.         public
  28.             constructor Create(AOwner:TComponent); override;
  29.             destructor  Destroy; override;
  30.         end;
  31.  
  32. {------------------------------------------------------------------}
  33. {--- Sizer --------------------------------------------------------}
  34. {------------------------------------------------------------------}
  35. {An example TMessageGrabber.
  36. Traps WMGetMinMaxInfo to give a specified maximum dimensions.
  37. Also resizes itself to give a specified Client area, regardless of
  38. how many lines the menu bar wraps onto}
  39.  
  40. type
  41.     TSizer = class(TMessageGrabber)
  42.     private
  43.         Resizing,SizeSet:boolean;
  44.         DesiredWidth,DesiredHeight:longint;
  45.         DeskSize:TPoint;
  46.         MinW,MinH,FullW,FullH:longint;
  47.         procedure SetDesiredWidth(NewWidth:longint);
  48.         procedure SetDesiredHeight(NewHeight:longint);
  49.     protected
  50.         procedure WMGetMinMaxInfo(var Msg:TMessage); message WM_GetMinMaxInfo;
  51.     public
  52.         constructor Create(AOwner:TComponent); override;
  53.         procedure Resize;
  54.         procedure SetSurfaceBounds(Width,Height:longint);
  55.     published
  56.         property SurfaceWidth:longint read DesiredWidth write SetDesiredWidth;
  57.         property SurfaceHeight:longint read DesiredHeight write SetDesiredHeight;
  58.     end;
  59.  
  60. procedure Register;
  61.  
  62. implementation
  63.  
  64. {------------------------------------------------------------------}
  65. {--- Message Grabber ----------------------------------------------}
  66. {------------------------------------------------------------------}
  67.  
  68. {Create:
  69. Override the WndProc of the owner window.
  70. Note that it will be a very bad idea to have several MessageGrabber
  71. components active at the same time, unless they are added and removed
  72. carefully in order}
  73.  
  74. constructor TMessageGrabber.Create(AOwner:TComponent);
  75. begin
  76. if not(AOwner is TWinControl) then
  77.     raise ENonWindowOwner.Create('Owner must be a windowed control');
  78. inherited Create(AOwner);
  79. OwnerWndProc:=TFarProc(GetWindowLong((Owner as TWinControl).Handle,gwl_WndProc));
  80. MyWndProc:=MakeObjectInstance(WndProc);
  81. SetWindowLong((Owner as TWinControl).Handle,gwl_WndProc,LongInt(MyWndProc));
  82. OwnerProcGrabbedQ:=True;
  83. end;
  84.  
  85. {Destroy:
  86. Removes the overriding window handler}
  87.  
  88. destructor TMessageGrabber.Destroy;
  89. begin
  90. if OwnerProcGrabbedQ then
  91.     SetWindowLong((Owner as TWinControl).Handle,gwl_WndProc,LongInt(OwnerWndProc));
  92. FreeObjectInstance(MyWndProc);
  93. inherited Destroy;
  94. end;
  95.  
  96. {WMDestroy:
  97. If WM_Destroy is sent to the owner, then when we get around to calling
  98. the Destroy method here, Owner will no longer be valid. So, there are
  99. two cases: Destroy is called without WMDestroy (ie component is removed
  100. at design-time) and WMDestroy is called first (ie owner is about to be
  101. destroyed)}
  102.  
  103. procedure TMessageGrabber.WMDestroy(var Msg:TWMDestroy);
  104. begin
  105. SetWindowLong((Owner as TWinControl).Handle,gwl_WndProc,LongInt(OwnerWndProc));
  106. OwnerProcGrabbedQ:=False;
  107. end;
  108.  
  109. {WndProc:
  110. For windowed controls, standard message handling is:
  111. the message is sent to WndProc, which calls Dispatch.
  112. Only windows controls have a WndProc. But Dispatch is a method
  113. of TObject, used for dispatching all message-based methods, not
  114. just Windows ones. This WndProc mimics that of a windowed control}
  115.  
  116. procedure TMessageGrabber.WndProc(var Msg:TMessage);
  117. begin
  118. Dispatch(Msg);
  119. end;
  120.  
  121. {DefaultHandler:
  122. The Dispatch method will attempt to dispatch the method, and failing
  123. will call DefaultHandler. If a message-response method calls
  124. its inherited method, where the inherited method is undefined, the
  125. message is also sent to the DefaultHandler.
  126. For a TMessageGrabber, DefaultHandler should pass any unhandled
  127. messages back to the owner}
  128.  
  129. procedure TMessageGrabber.DefaultHandler(var Msg);
  130. begin
  131. with TMessage(Msg) do
  132.     Result:=CallWindowProc(OwnerWndProc,(Owner as TWinControl).Handle,Msg,wParam,lParam);
  133. end;
  134.  
  135. {------------------------------------------------------------------}
  136. {--- Sizer --------------------------------------------------------}
  137. {------------------------------------------------------------------}
  138.  
  139. constructor TSizer.Create(AOwner:TComponent);
  140. var DeskRect:TRect;
  141. begin
  142. SizeSet:=false;
  143. inherited Create(AOwner);
  144. with Owner as TControl do
  145.     begin
  146.     SetSurfaceBounds(ClientWidth,ClientHeight);
  147.     FullW:=Width;
  148.     FullH:=Height;
  149.     end;
  150. Winprocs.GetClientRect(GetDesktopWindow,DeskRect);
  151. DeskSize.X:=DeskRect.Right-DeskRect.Left;
  152. DeskSize.Y:=DeskRect.Bottom-DeskRect.Top;
  153. SizeSet:=true;
  154. end;
  155.  
  156. procedure TSizer.SetSurfaceBounds(Width,Height:longint);
  157. begin
  158. DesiredWidth:=Width;
  159. DesiredHeight:=Height;
  160. with Owner as TForm do
  161.     begin
  162.     HorzScrollBar.Range:=DesiredWidth;
  163.     VertScrollBar.Range:=DesiredHeight;
  164.     end;
  165. end;
  166.  
  167. procedure TSizer.Resize;
  168.     procedure ShiftBounds(OldL,MaxW,Size:longint; var NewL,NewW:longint);
  169.     begin
  170.     if OldL>0 then begin
  171.         NewL:=Size-NewW;
  172.         if NewL<0 then begin
  173.             NewW:=NewW+NewL; NewL:=0; end; end;
  174.     end;
  175. var Desk:TRect;
  176.         MaxW,MaxH,OldW,OldH,NewL,NewT,NewW,NewH:longint;
  177. begin
  178. Resizing:=true;
  179. NewW:=0;   NewH:=0;
  180. with Owner as TControl do
  181.     begin
  182.  
  183. repeat
  184.     MaxW:=DeskSize.X-Left;
  185.     OldW:=NewW;
  186.     NewL:=Left;
  187.     NewW:=Width+(DesiredWidth-ClientWidth);
  188.     if NewW<MinW then NewW:=MinW;
  189.     if NewW>MaxW then ShiftBounds(Left,MaxW,DeskSize.X,NewL,NewW);
  190.  
  191.     repeat
  192.         MaxH:=DeskSize.Y-Top;
  193.         OldH:=NewH;
  194.         NewT:=Top;
  195.         NewH:=Height+(DesiredHeight-ClientHeight);
  196.         if NewH<MinH then NewH:=MinH;
  197.         if NewH>MaxH then ShiftBounds(Top,MaxH,DeskSize.Y,NewT,NewH);
  198.  
  199.         SetBounds(NewL,NewT,NewW,NewH);
  200.  
  201.     until OldH=NewH;
  202. until OldW=NewW;
  203.  
  204. FullW:=DesiredWidth+Width-ClientWidth;
  205. FullH:=DesiredHeight+Height-ClientHeight;
  206. if FullW<MinW then FullW:=MinW;
  207. if FullH<MinH then FullH:=MinH;
  208.  
  209. Resizing:=false;
  210. end;
  211. end;
  212.  
  213. procedure TSizer.WMGetMinMaxInfo(var Msg:TMessage);
  214. begin
  215. with PMinMaxInfo(Msg.lParam)^ do
  216.     begin
  217.     if (not SizeSet) then
  218.         begin
  219.         MinW:=ptMinTrackSize.X;
  220.         MinH:=ptMinTrackSize.Y;
  221.         end
  222.     else if (not Resizing) then
  223.         begin
  224.         ptMaxTrackSize.X:=FullW;
  225.         ptMaxTrackSize.Y:=FullH;
  226.         end;
  227.     end;
  228. end;
  229.  
  230. procedure TSizer.SetDesiredWidth(NewWidth:longint);
  231. begin
  232. SetSurfaceBounds(NewWidth,DesiredHeight);
  233. Resize;
  234. end;
  235.  
  236. procedure TSizer.SetDesiredHeight(NewHeight:longint);
  237. begin
  238. SetSurfaceBounds(DesiredWidth,NewHeight);
  239. Resize;
  240. end;
  241.  
  242. procedure Register;
  243. begin
  244. RegisterComponents('Additional', [TSizer]);
  245. end;
  246.  
  247. end.
  248.